#include "blowfish_openmp.h"

#define SWAP32(A,B) do{swap32temp=(A);(A)=(B);(B)=swap32temp;}while(0)

uint32_t swap32temp;

/**
 * Blowfish algorithm:
 * 
 * Divide x into two 32-bit halves: xL, xR
 * For i = 1 to 16:
 * xL = xL XOR Pi
 * xR = F(xL) XOR xR
 * Swap xL and xR
 * Next i
 * Swap xL and xR (Undo the last swap.)
 * xR = xR XOR P17
 * xL = xL XOR P18
 * Recombine xL and xR
 * 
 * Function F (see Figure 2):
 * Divide xL into four eight-bit quarters: a, b, c, and d
 * F(xL) = ((S1,a + S2,b mod 232) XOR S3,c) + S4,d mod 232
**/

inline uint32_t F(uint32_t X, uint32_t* S1, uint32_t* S2, uint32_t* S3, uint32_t* S4)
{
	uint8_t a,b,c,d;
	uint32_t result;
	
	a = X & 0xFF;
	b = (X & 0xFF00) >> 8;
	c = (X & 0xFF0000) >> 16;
	d = (X & 0xFF000000) >> 24;
	
	result = ((S1[a] + S2[b]) ^ S3[c]) + S4[d];
	return result;
}

void blowfish(uint64_t* x, uint32_t* P, uint32_t* S1, uint32_t* S2, uint32_t* S3, uint32_t* S4)
{
	int i;
	uint32_t xL, xR;
	
	xR = *x & 0xFFFFFFFF;
	xL = (*x & 0xFFFFFFFF00000000) >> 32;
	
	for(i = 0; i < 16; i++)
	{
		xL ^= P[i];
		xR ^= F(xL,S1,S2,S3,S4);
		SWAP32(xL,xR);
	}
	SWAP32(xL,xR);
	xR ^= P[16];
	xL ^= P[17];
	
	*x = ((uint64_t)xL << 32) | xR;
}

/*void blowfish_dec(uint64_t* x)
{
	int i;
	uint32_t xL, xR;
	
	xR = *x & 0xFFFFFFFF;
	xL = (*x & 0xFFFFFFFF00000000) >> 32;
	
	for(i = 17; i > 1; i--)
	{
		xL ^= P[i];
		xR ^= F(xL);
		SWAP32(xL,xR);
	}
	SWAP32(xL,xR);
	xR ^= P[1];
	xL ^= P[0];
	
	*x = ((uint64_t)xL << 32) | xR;
}*/

void gen_subkeys(uint32_t* P, uint32_t* S1, uint32_t* S2, uint32_t* S3, uint32_t* S4, uint32_t* key, int key_size)
{
	int i;
	uint32_t key_chunk;
	uint64_t zero_str = 0;
	
	#pragma omp parallel for shared(P) firstprivate(key_size,key) private(key_chunk)
	for(i = 0; i < 14; i++)
	{
		key_chunk = key[i%(key_size>>5)];
		P[i] ^= key_chunk;
		//printf("P%d gets %#.8x\n",i,key_chunk);
	}
	
	for(i = 0; i < 14; i+=2)
	{
		blowfish(&zero_str,P,S1,S2,S3,S4);
		P[i] = zero_str >> 32;
		P[i+1] = zero_str & 0xFFFFFFFF;
	}
	
	for(i = 0; i < 256; i+=2)
	{
		blowfish(&zero_str,P,S1,S2,S3,S4);
		S1[i] = zero_str >> 32;
		S1[i+1] = zero_str & 0xFFFFFFFF;
	}
	
	for(i = 0; i < 256; i+=2)
	{
		blowfish(&zero_str,P,S1,S2,S3,S4);
		S2[i] = zero_str >> 32;
		S2[i+1] = zero_str & 0xFFFFFFFF;
	}
	
	for(i = 0; i < 256; i+=2)
	{
		blowfish(&zero_str,P,S1,S2,S3,S4);
		S3[i] = zero_str >> 32;
		S3[i+1] = zero_str & 0xFFFFFFFF;
	}
	
	for(i = 0; i < 256; i+=2)
	{
		blowfish(&zero_str,P,S1,S2,S3,S4);
		S4[i] = zero_str >> 32;
		S4[i+1] = zero_str & 0xFFFFFFFF;
	}
}

